# -*- coding: utf-8 -*-
# @Author	: changfeng
# @Date		: 2025/9/13 13:57
# @Last Modified by:   changfeng
# @Last Modified time: 2025/9/13 13:57
# Thanks for your comments!


import logging

from bson import ObjectId
from pymongo import UpdateOne
from typing import List, Any, Dict

from pypinyin import lazy_pinyin

from src.basedata.application.commands import SyncDepartments, SyncPersons, SyncRouteOfAdministration, \
    SyncAdministrationFreq, SyncMedicines, SyncDiseaseCode
from src.basedata.infrastructure.common.unit_of_work import AbstractUnitOfWork
from src.basedata.domain.po import DepartmentPO, PersonPO, AppAdministrationMappingPO, AppFreqMappingPO, \
    MedicineLibraryPO, KnowledgeICD10MappingPO, ApplicationMedicineLibraryMapPO, MedicineLibraryListPO
from src.basedata.infrastructure.utils.commcon import datestr_to_sec

logger = logging.getLogger(__name__)


class BaseDataSaveService(object):
    """
    基础数据同步处理类
    """

    def __init__(self, uow: AbstractUnitOfWork):
        self._uow = uow

    async def convert_freq_cmd_to_po(self, app_code, data: SyncAdministrationFreq):
        return AppFreqMappingPO(
            app_id=app_code,
            app_freq=data.Code,
            app_freq_name=data.Name,
            app_freq_sp=data.Acronymy or ''.join(lazy_pinyin(data.Name, style=4)),
            app_take_time=data.TakeTime,
            interval=data.Interval,
            daliy_count=data.DailyCount
        )

    async def convert_administration_route_cmd_to_po(self, app_code, data: SyncRouteOfAdministration):
        return AppAdministrationMappingPO(
            app_id=app_code,
            app_adm=data.Code,
            app_adm_name=data.Name,
            app_adm_sp=data.Acronymy or ''.join(lazy_pinyin(data.Name, style=4)),
        )

    async def convert_icd10_cmd_to_po(self, app_code, data: SyncDiseaseCode):
        return KnowledgeICD10MappingPO(
            app_id=app_code,
            app_icd10_code=data.Code,
            app_icd10_fjm=data.Fjm,
            app_icd10_name=data.Name,
            app_pydm=data.Acronymy or ''.join(lazy_pinyin(data.Name, style=4)),
        )

    async def convert_department_cmd_to_po(self, app_id, data: SyncDepartments):
        return DepartmentPO(
            code=data.Code,
            name=data.Name,
            parent_id=None,
            app_id=ObjectId(app_id),
            category=data.Category.value,
            address=data.Address,
            name_acronym=''.join(lazy_pinyin(data.NameAcronym or '', style=4)),
            name_spell=''.join(lazy_pinyin(data.NameSpell or '')),
        )

    async def convert_person_cmd_to_po(self, app_id, data: SyncPersons):
        birthdate = datestr_to_sec(data.Birthdate) * 1000 if data.Birthdate else None
        return PersonPO(
            app_id=ObjectId(app_id),
            employee_number=data.Code,
            name=(data.Name or '').replace(" ", ""),
            type=data.Type.value,
            gender=data.Gender.value,
            dept_code=data.DeptCode,
            pydm=data.Acronymy or '',
            birthdate=birthdate,
            telephone=data.Telephone or '',
            his_code=data.HISCode or '',
            title=data.Title or '',
            country=data.Country or '',
            id_number=data.IDNumber or ''
        )

    async def convert_medicine_cmd_to_po(self, library_id, data: SyncMedicines):
        return MedicineLibraryListPO(
            library_id=ObjectId(library_id),
            std_medicine_id=None,
            code=data.Code,
            medicine_code=data.Code,
            med_nation_ins_code=data.MedNationInsCode,
            bar_code=data.BarCode or '',
            medicine_name=data.Name,
            english_name=data.EnglishName,
            trade_name=data.TradeName,
            chemistry_name=data.ChemistryName,
            acronymy=data.Acronymy,
            approval_no=data.ApprovalNo,
            spec=data.Spec,
            uom=data.Uom,
            dosage_form=data.DosageForm,
            manufacturer=data.Manufacturer,
            package_spec=data.PackageSpec,
            packing_uom=data.PackageUom or '',
            packing_min_uom=data.PackageMinUom or '',
            cn_west_flag=data.CNWestFlag.value,
            basic_drug=data.BasicDrug,
            antibacterial=data.Antibacterial,
            antibac_type=data.AntibacType.value,
            ddd=data.DDD,
            total_qty=data.TotalQTY,
            packing_min_qty=data.PackgeMinQTY,
            injection=data.Injection,
            antitumor=data.Antitumor,
            toxic=data.Toxic
        )

    async def get_medicine_library(self, app_info):
        # 查询机构有没有对应的药品库
        app_lib_map = await self._uow.app_med_lib_map.get_by_app_id(app_info.get("_id"))
        if not app_lib_map:
            library_id = await self._uow.medicine_lib.add(MedicineLibraryPO(
                name=app_info.get("name") + "药品目录",
                type="1000",
                remark=app_info.get("name") + "药品目录",
            ))
            await self._uow.app_med_lib_map.add(ApplicationMedicineLibraryMapPO(
                app_id=ObjectId(app_info.get("_id")),
                library_id=ObjectId(library_id)
            ))

        else:
            library_id = str(app_lib_map.get("library_id"))
        return library_id

    async def update_department_parent(self, app_id: str, data: List[SyncDepartments]):
        # 处理父类科室
        parent_codes = [d.ParentCode for d in data if d.ParentCode]
        if not parent_codes:
            return None

        dept_data = await self._uow.department.get_data_by_codes(app_id, parent_codes)
        if not dept_data:
            return None
        dept_code_parent_id_map = {d.get("code"): d.get("_id") for d in dept_data}
        updates_parent = []
        for item in data:
            parent_id = dept_code_parent_id_map.get(item.Code)
            if not parent_id:
                continue
            update_query = {
                "$set": {"parent_id": ObjectId(parent_id)}
            }
            filter_query = {"app_id": ObjectId(app_id), "code": item.Code, "obsoleted": False}
            updates_parent.append(UpdateOne(filter_query, update_query))
            if updates_parent:
                await self._uow.department.batch_update(updates_parent)

    async def save_department(self, app_info, data_list: List[SyncDepartments]):
        save_data = []
        app_id = app_info.get("_id")

        unique_by_last = {}
        for item in data_list:
            unique_by_last[item.Code] = item  # 重复时覆盖
        unique_list2 = list(unique_by_last.values())

        for item in unique_list2:
            po = await self.convert_department_cmd_to_po(app_id, item)
            save_data.append(po)
        if save_data:
            await self._uow.department.batch_save(save_data)
            await self.update_department_parent(app_id, unique_list2)

    async def save_person(self, app_info, data_list):
        save_data = []
        app_id = app_info.get("_id")
        app_code = app_info.get("code")

        unique_by_last = {}
        for item in data_list:
            unique_by_last[item.Code] = item  # 重复时覆盖
        unique_list2 = list(unique_by_last.values())

        for item in unique_list2:
            po = await self.convert_person_cmd_to_po(app_id, item)
            save_data.append(po)
        if save_data:
            await self._uow.person.batch_save(save_data)
            await self._uow.person.save_data_to_redis(app_code, save_data)

    async def save_administration(self, app_info, data_list: List[SyncRouteOfAdministration]):
        app_code = app_info.get("code")

        unique_by_last = {}
        for item in data_list:
            unique_by_last[item.Code] = item  # 重复时覆盖
        unique_list2 = list(unique_by_last.values())
        save_data = []
        for item in unique_list2:
            po = await self.convert_administration_route_cmd_to_po(app_code, item)
            save_data.append(po)
        if save_data:
            await self._uow.app_administration_map.batch_save(save_data)

    async def save_freq(self, app_info: Dict[str, Any], data_list: List[SyncAdministrationFreq]):
        app_code = app_info.get("code")

        unique_by_last = {}
        for item in data_list:
            unique_by_last[item.Code] = item  # 重复时覆盖
        unique_list2 = list(unique_by_last.values())
        save_data = []

        for item in unique_list2:
            po = await self.convert_freq_cmd_to_po(app_code, item)
            save_data.append(po)
        if save_data:
            await self._uow.app_freq_map.batch_save(save_data)

    async def save_medicine(self, app_info, data_list: List[SyncMedicines]):
        library_id = await self.get_medicine_library(app_info)

        unique_by_last = {}
        for item in data_list:
            unique_by_last[item.Code] = item  # 重复时覆盖
        unique_list2 = list(unique_by_last.values())
        save_data = []
        for item in unique_list2:
            po = await self.convert_medicine_cmd_to_po(library_id, item)
            save_data.append(po)
        if save_data:
            await self._uow.medicine_list.batch_save(save_data)
            await self._uow.medicine_list.save_data_to_redis(library_id, save_data)

    async def save_icd10(self, app_info, data_list):
        app_code = app_info.get("code")

        unique_by_last = {}
        for item in data_list:
            unique_by_last[item.Code] = item  # 重复时覆盖
        unique_list2 = list(unique_by_last.values())
        save_data = []
        for item in unique_list2:
            po = await self.convert_icd10_cmd_to_po(app_code, item)
            save_data.append(po)

        if save_data:
            await self._uow.icd10.batch_save(save_data)
